/*
 *  Copyright (c) 2001 Sun Microsystems, Inc.  All rights
 *  reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in
 *  the documentation and/or other materials provided with the
 *  distribution.
 *
 *  3. The end-user documentation included with the redistribution,
 *  if any, must include the following acknowledgment:
 *  "This product includes software developed by the
 *  Sun Microsystems, Inc. for Project JXTA."
 *  Alternately, this acknowledgment may appear in the software itself,
 *  if and wherever such third-party acknowledgments normally appear.
 *
 *  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA"
 *  must not be used to endorse or promote products derived from this
 *  software without prior written permission. For written
 *  permission, please contact Project JXTA at http://www.jxta.org.
 *
 *  5. Products derived from this software may not be called "JXTA",
 *  nor may "JXTA" appear in their name, without prior written
 *  permission of Sun.
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 *  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 *  SUCH DAMAGE.
 *  ====================================================================
 *
 *  This software consists of voluntary contributions made by many
 *  individuals on behalf of Project JXTA.  For more
 *  information on Project JXTA, please see
 *  <http://www.jxta.org/>.
 *
 *  This license is based on the BSD license adopted by the Apache Foundation.
 *
 *  $Id: MapPanel.java,v 1.2 2006/07/13 05:26:37 nano Exp $
 */

package net.jxta.myjxta.misc.beam;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;

public class MapPanel extends JPanel implements MouseMotionListener, MouseListener {

    private Image img;
    private JLabel status = null;
    private double gpsx0 = 0.0;
    private double gpsy0 = 0.0;
    private double gpsx1 = 0.0;
    private double gpsy1 = 0.0;
    private Hashtable<String, Hashtable<String, Properties>> locations = null;
    private Hashtable<String, String> iconloc = null;
    private Image simg = null; //support one icon resource currently
    private JPopupMenu popup = null;
    private boolean popupIsVisible = false;
    private String currloc = null;

    public MapPanel(URL imgurl, JLabel status) {
        System.out.println("MapPanel imgurl = " + imgurl.toString());
        this.status = status;
        locations = new Hashtable<String, Hashtable<String, Properties>>();
        iconloc = new Hashtable<String, String>();
        ImageIcon icon = new ImageIcon(imgurl);
        img = icon.getImage();
        addMouseMotionListener(this);
        addMouseListener(this);

        try {
            URL iconurl = getClass().getResource("resources/sensorIcon.gif");
            ImageIcon sicon = new ImageIcon(iconurl);
            simg = sicon.getImage();
        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }

    public Image getImage() {
        return img;
    }

    public void setImage(Image img) {
        this.img = img;
    }

    public void setGPSUpperLeft(double x, double y) {
        System.out.println("set upper left gps");
        this.gpsx0 = x;
        this.gpsy0 = y;
    }

    public void setGPSLowerRight(double x, double y) {
        System.out.println("set lower right gps");
        this.gpsx1 = x;
        this.gpsy1 = y;
    }

    /**
     * method to add a sensor.  The way MapPanel draws must be fast
     * and what we will do is to take the properties file for a sensor
     * and extract the gps coordinates and insert into a hashtable
     * using the combined gpsx and gpsy coordinate to two decimal
     * places as the hash.  At each hash key, we store a Hashtable of
     * Properties representing 1 or more sensors at that relative
     * GPS location.  The nested Hashtable is indexed by sensorID.
     * The MapPanel will show only one icon for a location
     * on the map, but post a popup display of all SIDs.
     */
    public void addSensor(Properties p) {
        try {
            // reduce gpsx and gpsy coordinate to 1 decimal place
            // then generate a locationkey
            double gpsx = Double.parseDouble(p.getProperty("gpsx"));
            double gpsy = Double.parseDouble(p.getProperty("gpsy"));
            //System.out.println("addSensor: longitude = " + gpsx + ", latitude = " + gpsy);
            String lochash = getGPSLocationKey(gpsx, gpsy, 2);
            String lochash2 = getGPSLocationKey(gpsx, gpsy, 1);
            String sid = p.getProperty("sid");
            System.out.println("MapPanel added sid [" + sid + "] at: " + lochash);

            // see if current location already exists and
            // if not, create a new hashtable and nest into
            // locations
            Hashtable<String, Properties> sensors = (locations.get(lochash));
            if (sensors == null) {
                sensors = new Hashtable<String, Properties>();
                locations.put(lochash, sensors); // high res location sensor
                iconloc.put(lochash2, lochash); // low res for icon mouseover
            }

            // add the specific sensor properties into specific hashtable
            // of sensors at this specific location
            sensors.put(sid, p);

        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }

    private String getGPSLocationKey(double x, double y, int decplaces) {

        if (decplaces <= 0) decplaces = 2;
        double divisor = 1.0;
        for (int i = 0; i < decplaces; i++) {
            divisor *= 10.0;
        }

        double xd = ((int) (x * divisor - 0.5)) / divisor;
        double yd = ((int) (y * divisor + 0.5)) / divisor;
        String key = Double.toString(xd) + "|" + Double.toString(yd);
        return key;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Dimension dim = getSize();
        int x0 = 0;
        int y0 = 0;
        int imgW = 0;
        int imgH = 0;

        if (img != null) {
            imgW = img.getWidth(this);
            imgH = img.getHeight(this);
            x0 = (dim.width - imgW) / 2;
            y0 = (dim.height - imgH) / 2;
            g.drawImage(img, x0, y0, this);

            // now draw the sensor icon at each location
            Enumeration<String> loc = locations.keys();
            while (loc.hasMoreElements() && simg != null) {
                String pos = loc.nextElement();
                String lon = pos.substring(0, pos.indexOf("|"));
                String lat = pos.substring(pos.indexOf("|") + 1);
                double gpsx = Double.parseDouble(lon);
                double gpsy = Double.parseDouble(lat);
                //System.out.println("Paint Icon: longitude = " + gpsx + ", latitude = " + gpsy);
                double fractionx = (gpsx - gpsx0) / (gpsx1 - gpsx0);
                double fractiony = (gpsy - gpsy0) / (gpsy1 - gpsy0);
                int x1 = x0 + (int) (fractionx * imgW) - 10;
                int y1 = y0 + (int) (fractiony * imgH) - 10;
                g.drawImage(simg, x1, y1, this);
            }
        }
    }

    public void mouseDragged(MouseEvent e) {
        mouseMoved(e);
    }

    public void mouseMoved(MouseEvent e) {
        if (img != null) {

            Dimension dim = getSize();
            int imgw = img.getWidth(this);
            int imgh = img.getHeight(this);
            int x0 = (dim.width - imgw) / 2;
            int y0 = (dim.height - imgh) / 2;
            int x = e.getX();
            int y = e.getY();

            double diffgpsx = gpsx1 - gpsx0;
            double diffgpsy = gpsy1 - gpsy0;

            double currgpsx = ((int) (10000 * (gpsx0 + diffgpsx * (x - x0) / imgw) + 0.5)) / 10000.0;
            double currgpsy = ((int) (10000 * (gpsy0 + diffgpsy * (y - y0) / imgh) + 0.5)) / 10000.0;


            status.setText("GPS coordinates:  Long. = " + currgpsx + ",  Lat. = " + currgpsy);
            //System.out.println("GPS coordinates:  Lat = " + currgpsy + ",  Long. = " + currgpsx);

            // now create a popup menu if inside a sensor - may need to reduce
            // accuracy for this map to 1 decimal place

            String lochash = getGPSLocationKey(currgpsx, currgpsy, 1);
            String sensor = (iconloc.get(lochash));

            if (sensor != null) { // location exists, make popup visible
                if (currloc != null && currloc.equals(lochash)) { // is same popup
                    if (!popupIsVisible) {
                        popup.show(e.getComponent(), e.getX(), e.getY());
                    }
                } else {
                    // hide and dispose of old popup
                    if (popup != null) {
                        popup.setVisible(false);
                        popup = null;
                    }

                    // create new popup
                    Hashtable sensors = locations.get(sensor);
                    Enumeration keys = sensors.keys();
                    popup = new JPopupMenu();
                    while (keys.hasMoreElements()) {
                        Properties p = (Properties) (sensors.get(keys.nextElement()));
                        if (p != null) {
                            String sid = p.getProperty("sid");
                            String desc = p.getProperty("desc");
                            popup.add(new JMenuItem(sid + ": " + desc));
                        }
                    }
                    popup.show(e.getComponent(), e.getX(), e.getY());
                    popupIsVisible = true;
                    currloc = lochash;
                }

            } else { // make sure nothing shows
                if (popup != null) popup.setVisible(false);
                popup = null;
                popupIsVisible = false;
                currloc = null;
            }
        }
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
        // make sure to hide the popup.
        if (popup != null) {
            popup.setVisible(false);
            popup = null;
            currloc = null;
            popupIsVisible = false;
        }
    }

}
